<?
//Класс поставщик для работы с кешем
class Cache {
  private $lock=false;
  
  public static $last_id=false;
  
	protected static $db=false;
	protected static $states=array();
	protected static $temp=false;
	protected static $forever=false;
	
	
	const day=86400;					// 24*60*60 - день
	const month=2592000;			// 24*60*60*30 - мес.
	const year=31536000;			// 24*60*60*365 - год
	const forever=157680000; // 24*60*60*365*5 - 5 лет


  protected static $_instance;
	private function __construct(){}
	private function __clone(){}
	public static function inst(){
	  if( null===self::$_instance ){
	    self::$_instance=new self();
		}
		return self::$_instance;
	}

	protected $errors=array('err'=>array(),'wrn'=>array());
	protected function error($msg){ $this->errors['err'][]=$msg; return false;}
	protected function warning($msg){ $this->errors['wrn'][]=$msg; return false;}
	public function getError(){ return $this->errors['err'][ count($this->errors['err'])-1 ]; }
	public function getErrors(){ return $this->errors['err']; }
	public function getWarning(){ return $this->errors['wrn'][ count($this->errors['wrn'])-1 ]; }
	public function getWarnings(){ return $this->errors['wrn']; }

	public function init_db(){
	  //$GLOBALS['jApi']->db;
	  if( !empty(self::$db) ) return true;
	  self::$db=jApi::inst()->getDB()->getPDO();
	  return true;
	  /*
	  include $_SERVER['DOCUMENT_ROOT'].API::$dbConf;
	  
	  try {
		    self::$db = new PDO('mysql:dbname='.$db_prm['db'].';host='.$db_prm['server'], $db_prm['usn'], $db_prm['pwd']);
		} catch (PDOException $e) {
		    return $this->error( $e->getMessage() );
		}
		if(!empty($db_prm['set_names'])) self::$db->exec ( "SET NAMES '".$db_prm['set_names']."'" );
		return true;
		*/
	}
	
	function id($string){
	  if( strlen($string)==34 && substr($string, 0, 2)=='ci' ) return $string;
		return 'ci'.substr(md5($string), 0,32);
	}

	function get($id){
	  if( $this->lock ) return false;
	  if( !$this->init_db() )	return $this->error('DB connect error');
	  
		//Подготовка запроса
	  if( empty( self::$states['get'] ) ){
		  try{
		    $sql="SELECT cache_content FROM cache WHERE `cache_id`=:id AND `cache_dead`>:curTime ORDER BY cache_create DESC LIMIT 0,1";
		    self::$states['get']=self::$db->prepare($sql,array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
			}catch(Exception $e){
			  return $this->error('Prepare get query exception '.$e->getMessage() );
			}
		}
		//echo '<pre class="debug">'.print_r ( array( ':id' => $id, ':curTime' => time() ) ,true).'</pre>';
		//Выполнение запроса
		if(!self::$states['get']->execute(
			array( ':id' => self::id($id), ':curTime' => time() )
		)) return $this->error('Fail get statment execute' );
		$row = self::$states['get']->fetch();
		
	  self::$last_id=$id;
	  if(empty($row)) return false;
	  return unserialize( $row['cache_content'] );
	}
	
	//Метод запоминает данные для последующего сохранения
	function prepare($id,$data=false){
	  if( $this->lock ) return false;
	  //Если задана очистка подготовленного сохранения
	  if( $id=='clear' ){	self::$temp=false; return true; }
	  //Если не передано что готовить
	  if( !$data) return $this->error('Data for preparing empty');

	  self::$temp=array(
	    'id'=>$id,
	    'data'=>$data,
		);
	  return true;
	}
	
	function set($id=false,$data=false,$period_sec=false){
	  if( $this->lock ) return false;
	  //Если что сохранять не передано и сохранение не подготовлено заранее - ошибка
	  if( (!$id || !$data)  && !self::$temp ) return $this->error('Data for save not found');

	  if(!$period_sec) $period_sec=1728000; // 24*60*60*20 - 20 дней
	  else if(!is_numeric($period_sec)) $period_sec=self::day;
	  
		if( !$id || !$data ){
		  $id=self::$temp['id'];
		  $data=self::$temp['data'];
		  self::prepare('clear');
		}
		
		if( !$this->init_db() )
			$this->error('DB connect error');
		
		//Подготовка запроса
	  if( empty( self::$states['set'] ) ){
		  try{
		    $sql="REPLACE INTO cache SET cache_id=:id, cache_content=:content, cache_create=:create, cache_dead=:dead,cache_comm=:comm";
      	self::$states['set']=self::$db->prepare($sql);
			}catch(Exception $e){
			  return $this->error('Prepare get query exception '.$e->getMessage() );
			}
		}
		
		//Выполнение запроса
		//$now=mktime();
    $now=time();
		$dead=time()+$period_sec;
		
		$qdata=array(
			':id' => self::id($id),
			':create' => $now,
			':dead'=>$dead,
			':content'=>serialize($data),
			':comm'=>$id
		);
		
		if(
			!self::$states['set']->execute(
				$qdata
			)
		)
			return $this->error('Fail set statment execute' );

	  self::$last_id=$id;
	  
	  unset( $now,$dead,$data,$period_sec,$qdata,$sql );
	  return true;
	}
	
	function remove($id){
	  if( $this->lock ) return false;
	  if(empty($id)) return $this->error('cant remove record with empty id' );
	  if( !$this->init_db() )	return $this->error('DB connect error');
	  self::$db->query( "DELETE FROM cache WHERE cache_id='". self::$db->quote($id) ."'" );
	}
}
?>